<!--
  - 拉曼项目
 -->

<!-- 视图层 -->
<template><header-comp />

<!-- TFjs初始化组件 -->
<tfjsInit />

<!-- 业务介绍：卡片容器 -->
<uni-card>
  <!-- 标题 -->
  <uni-section
    title="业务介绍"
    subtitle="拉曼项目，拉曼光谱数据预测。"
    type="line"
  >
    <!-- 内容 -->
    <view><text space="ensp">
      {{ ramanIntro }}
    </text></view>
  </uni-section>
</uni-card>

<!-- 训练结果呈现：卡片容器 -->
<uni-card>
  <!-- 容器：机器学习程序 -->
  <uni-section
    title="机器学习程序内容"
    subtitle="可视化机器学习训练及结果。"
    type="line"
  >

    <!-- 容器：迭代次数设置 + 启动训练 -->
    <uni-section
      title="● 迭代次数："
      subTitle="默认20。手机演示建议20；电脑建议100+"
    >
      <!-- 迭代次数输入框 -->
      <uni-easyinput
        :disabled="(trainRef != 0)"
        v-model="epochCounts"
        type="number"
        placeholder="请输入迭代次数"
        trim="all" :clearable="false"
      />
      <!-- 训练按钮 -->
      <button
        v-if="!trainRef"
        :disabled="!tfBackendRef"
        @click="ramanMain()"
        type="primary"
      >
        开始训练
      </button>
    </uni-section>

    <!-- 容器：计算历程。条件渲染：存在记录才渲染 -->
    <uni-section
      v-if="logArrRef[0]"
      title="● 计算历程记录如下："
    >
      <!-- 计算历程：表格容器 -->
      <uni-table border stripe>
        <!-- 表格标题行 -->
        <uni-tr>
          <uni-th align="center">序号</uni-th>
          <uni-th>内容</uni-th>
        </uni-tr>
        <!-- 表格内容行 -->
        <uni-tr v-for="(log, index) in logArrRef" :key="index">
          <uni-td align="center">{{ index + 1 }}</uni-td>
          <uni-td><text>{{ log }}</text></uni-td>
        </uni-tr>
      </uni-table>
      <!-- 打开图表板容器及按钮 -->
      <view class="center"><button
        @click="showVisor()"
        size="mini" type="primary"
      >
        打开图表板
      </button></view>
    </uni-section>

    <!-- 容器：各类下载 -->
    <uni-section
      v-if="trainRef == 2"
      title="● 模型文件&历程数据下载"
    >
      <!-- 下载模型容器及按钮 -->
      <view class="center"><button
        v-if="trainRef == 2"
        @click="downloadModel()"
        size="mini" type="primary"
      >
        下载模型[拓扑框架]&[权重参数]
      </button></view>
      <!-- 下载训练记录容器及按钮 -->
      <view class="center"><button
        v-if="trainRef == 2"
        @click="saveTrainLog()"
        size="mini" type="primary"
      >
        下载训练历程数据
      </button></view>
    </uni-section>

  </uni-section>
</uni-card>

</template>

<!-- 逻辑层 -->
<script setup>
// // 导入tfjs库和tfjs-visor库
// import * as tf from "@tensorflow/tfjs"
// import * as tfvis from "@tensorflow/tfjs-vis"
// 导入vue的onMounted、ref方法
import { shallowRef, ref } from "vue"
// 导入TF初始化组件
import tfjsInit from "../index/tfjs-init.vue"
// 导入机器学习库的公共对象、公共方法
import {
  tfBackendRef,
  showVisor,
  downloadTrainHistoryToXlsx,
} from "../../scripts/app_common.js"

// 导入相关模块
import { dataTensor } from "../../scripts/tfjs/1_dataset-tensor.js"
import { layersModel } from "../../scripts/tfjs/2_layers-model.js"
import { modelCompile } from "../../scripts/tfjs/3_model_compile.js"
import { trainFix } from "../../scripts/tfjs/4_train-fix.js"


/**
 * @对象
 */
// 迭代次数对象
const epochCounts = shallowRef(20)
// 训练状态对象
const trainRef = shallowRef(0)
// 训练记录对象
const logArrRef = ref([])
// 模型对象
let model = null
// 训练记录
let trainHistory = null
// 拉曼业务的介绍
const ramanIntro = `  ● 特别鸣谢：
    数据提供-李东建
  ● 业务概述：
    拉曼光谱数据 => 待测物定性+定量预测
    特征：各波数下的光强信号，1600组。
    标签：待测物A、B的浓度，2组。
    数据集：300条光谱样本数据。
    模型各层情况：详情见图表栏-模型信息。
    模型编译参数：优化器为ADAM，损失函数为平均绝对误差MAE，辅助评估指标为均方误差MSE。
    训练超参：训练集划出10%作为验证集，每次迭代打乱(shuffle)数据集，迭代轮次数可调，其它超参(如学习率等)维持默认。
`

/**
 * @启动方法 生命周期钩子，组件加载完毕后执行
 */
// onMounted(() => {})

/**
 * @主方法 串联所有方法
 */
async function ramanMain() {
  // 开始训练记号
  trainRef.value = 1

  // 1. 获取数据并乱序后预处理为归一化张量
  // 解构赋值
  const {
    // 特征归一化张量，及逆归一化时需要的最大值、最小值张量
    featureTensorNormalized,
    featureTensorMax,
    featureTensorMin,
    // 标签归一化张量，及逆归一化时需要的最大值、最小值张量
    labelTensorNormalized,
    labelTensorMax,
    labelTensorMin,
  } = dataTensor(logArrRef.value)

  // 2. 构建模型
  model = layersModel(logArrRef.value)

  // 3. 编译模型
  modelCompile(model, logArrRef.value)

  // 4. 训练模型
  trainHistory = await trainFix(
    model,
    featureTensorNormalized,
    labelTensorNormalized,
    epochCounts.value || 20,
    logArrRef.value
  )

  // 训练完成记号
  trainRef.value = 2

}

/**
 * @downloadModel 保存模型
 * @function
 */
// 保存模型
function downloadModel() {
  model.save("downloads://model")
  console.log("下载模型")
  logArrRef.value.push("下载模型。")
  // // *. 读取模型
  // const model = await tf.loadLayersModel("./demo-model.json")
}

/**
 * @saveTrainLog 保存训练记录
 * @function
 */
function saveTrainLog() {
  // 直接调用现成方法
  downloadTrainHistoryToXlsx(trainHistory)
  console.log("下载训练里程数据")
  logArrRef.value.push("下载训练里程数据。")
}


</script>